package wre.data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import wre.Word;
import wre.logic.InputParser;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

/**
 * The Class WordDAO contains a HashMap of all of the words that could be used as 
 * phrases as well as the associations to the retort. This method also has a datastore 
 * for all of the words that are used in the WRE.
 * 
 * @author Adam Smith
 */
public class WordDAO {
	
	/**
	 * Gets the single instance of WordDAO.
	 *
	 * @return single instance of WordDAO
	 */
	public static WordDAO getInstance() {
		WordDAO wordDAO = new WordDAO();
		PreparedQuery query = wordDAO.datastore
				.prepare(new Query("WordEntity"));
		for (Entity result : query.asIterable()) {
			Word word = new Word(((Long) result.getProperty("id")).intValue(),
					(String) result.getProperty("word"),
					((Long) result.getProperty("count")).intValue());
			wordDAO.words.put(word.getWord(), word);
		}
		return wordDAO;
	}

	/**
	 * The main method.
	 *
	 * @param args the arguments
	 */
	public static void main(String[] args) {
		WordDAO dao = getInstance();
		dao.addPhrase(470518469, "Hey, watch your mouth", false);
		dao.addPhrase(111510280, "Make sure it's long enough", false);
		dao.addPhrase(-1310051655, "YOU don't make any sense", false);
		dao.addPhrase(-1991051528, "you are an idiot", false);
		dao.addPhrase(395349139,
				"I heard some people talking about that the other day", false);
		dao.addPhrase(111510280, "Push harder", false);
		try {
			dao.writeData();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/** The words. */
	private Map<String, Word> words;

	/** The datastore. */
	private DatastoreService datastore;

	/**
	 * Instantiates a new word dao by getting an instance of the datastore and creating a new HashMap for the words
	 */
	private WordDAO() {
		datastore = DatastoreServiceFactory.getDatastoreService();
		words = new HashMap<String, Word>();
	}

	/**
	 * Adds the phrase by passing the string into the input parser and associating each of the words to 
	 * the ID that was passed in to the method.
	 *
	 * @param id the id
	 * @param phrase the phrase
	 * @param updateCount the update count
	 */
	public void addPhrase(int id, String phrase, boolean updateCount) {
		InputParser inputParser = InputParser.getInstance();
		List<String> synonyms;
		try {
			synonyms = inputParser.parseInput(phrase);

			for (String word : synonyms) {
				addWord(id, word, updateCount);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Adds the word  to the Map only if the word has a length greater than 
	 * 2 characters long
	 *
	 * @param id the id
	 * @param word the word
	 * @param updateCount the update count
	 */
	public void addWord(int id, String word, boolean updateCount) {
		String myWord = word.trim().toLowerCase();
		if (myWord.length() > 2) {
			if (words.containsKey(myWord) && updateCount) {
				words.get(myWord).setCount(words.get(myWord).getCount() + 1);
			} else if (!words.containsKey(myWord)) {
				words.put(myWord, new Word(id, myWord, 0));
			}
		}
	}

	/**
	 * Removes all of the words from the datastore.
	 */
	public void deleteAll() {
		PreparedQuery query = datastore.prepare(new Query("WordEntity"));
		for (Entity result : query.asIterable()) {
			datastore.delete(result.getKey());
		}
	}

	/**
	 * Returns the Map of words
	 *
	 * @return the words
	 */
	public Map<String, Word> getWords() {
		return words;
	}

	/**
	 * Sets the Map of words to the argument passed in
	 *
	 * @param words the words
	 */
	public void setWords(Map<String, Word> words) {
		this.words = words;
	}

	/**
	 * Writes the data that is stored in the HashMap to the datastore 
	 *
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public void writeData() throws IOException {
		List<Entity> newWords = new ArrayList<Entity>();
		Iterator<Entry<String, Word>> iterator = words.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, Word> entry = iterator.next();
			String key = entry.getKey();
			Word word = entry.getValue();
			if (words.containsKey(key)) {
				Entity entity = new Entity("WordEntity");
				entity.setProperty("word", word.getWord());
				entity.setProperty("id", word.getId());
				entity.setProperty("count", word.getCount());
				newWords.add(entity);
			}
		}
		datastore.put(newWords);

	}

}
